﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using ColorConsole;
using Newtonsoft.Json.Linq;

namespace PublishToFir
{
	class MainClass
	{
		static IConsoleWriter o = new ConsoleWriter();


		public static void Main(string[] args)
		{

			if (args.Length != 6)
			{
				o.WriteLine("{path} {bundle_id} {msg} {token} {name} {version} ", ConsoleColor.Red);
				return;
			}

			var path = args[0];
			var bundle_id = args[1];
			var msg = args[2];
			var token = args[3];
			var name = args[4];
			var version = args[5]; 
			Publish(path,bundle_id, msg,token,name,version,version);


			while (true); 

		}

		public static async void Publish(string path,string bundle_id, string msg,string token,string name,string version,string build)
		{
			 
			var url = "http://api.fir.im/apps";
		 
			var handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip };

			var type = path.Contains("apk") ? "android" : "ios";
		 
			try
			{
				using (var http = new HttpClient(handler))
				{

					var content = new FormUrlEncodedContent(new Dictionary<string, string>()
 					{
						{"bundle_id",bundle_id},
						{"type", type},
						{"api_token",token}
					});


					var response = await http.PostAsync(url, content);
					var r = await response.Content.ReadAsStringAsync();

					var json = JObject.Parse(r);

					var uploadtoken = json["cert"]["binary"]["token"].Value<string>();
					var uploadkey = json["cert"]["binary"]["key"].Value<string>();
					var uploadurl = json["cert"]["binary"]["upload_url"].Value<string>();


					var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
					byte[] data = new byte[fs.Length];
					fs.Read(data, 0, data.Length);
					fs.Close();

					var postParameters = new Dictionary<string, object>();
					postParameters.Add("key", uploadkey);
					postParameters.Add("token", uploadtoken);
					postParameters.Add("file", new FormUpload.FileParameter(data, Path.GetFileName(path), "application/binary"));
					postParameters.Add("x:name", name);
					postParameters.Add("x:version", version);
					postParameters.Add("x:build", build);
					postParameters.Add("x:changelog", msg);  
					o.WriteLine("Uploading...", ConsoleColor.Yellow);
					HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(uploadurl, null,postParameters);

					// Process response
					StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());
					string fullResponse = responseReader.ReadToEnd();
					webResponse.Close();
					o.WriteLine(fullResponse);
				}

			}
			catch (Exception ex)
			{
				o.WriteLine(ex,ConsoleColor.Red);
				Environment.Exit(-1);
			}
			o.WriteLine("Upload Success", ConsoleColor.Green);
			Console.ReadKey();
			Environment.Exit(0);
		
		} 
	}


	#region
	// Implements multipart/form-data POST in C# http://www.ietf.org/rfc/rfc2388.txt
	// http://www.briangrinstead.com/blog/multipart-form-post-in-c
	public static class FormUpload
	{
		private static readonly Encoding encoding = Encoding.UTF8;
		public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters)
		{
			string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
			string contentType = "multipart/form-data; boundary=" + formDataBoundary;

			byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);

			return PostForm(postUrl, userAgent, contentType, formData);
		}
		private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData)
		{
			HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;

			if (request == null)
			{
				throw new NullReferenceException("request is not a http request");
			}

			// Set up the request properties.
			request.Method = "POST";
			request.ContentType = contentType;
			request.UserAgent = userAgent;
			request.CookieContainer = new CookieContainer();
			request.ContentLength = formData.Length;

			// You could add authentication here as well if needed:
			// request.PreAuthenticate = true;
			// request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;
			// request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("username" + ":" + "password")));

			// Send the form data to the request.


			using (Stream requestStream = request.GetRequestStream())
			{ 
				requestStream.Write(formData, 0, formData.Length); 
				requestStream.Close();
			}

			return request.GetResponse() as HttpWebResponse;
		}

		private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
		{
			Stream formDataStream = new System.IO.MemoryStream();
			bool needsCLRF = false;

			foreach (var param in postParameters)
			{
				// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
				// Skip it on the first parameter, add it to subsequent parameters.
				if (needsCLRF)
					formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));

				needsCLRF = true;

				if (param.Value is FileParameter)
				{
					FileParameter fileToUpload = (FileParameter)param.Value;

					// Add just the first part of this param, since we will write the file data directly to the Stream
					string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n",
						boundary,
						param.Key,
						fileToUpload.FileName ?? param.Key,
						fileToUpload.ContentType ?? "application/octet-stream");

					formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));

					// Write the file data directly to the Stream, rather than serializing it to a string.
					formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
				}
				else
				{
					string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
						boundary,
						param.Key,
						param.Value);
					formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
				}
			}

			// Add the end of the request.  Start with a newline
			string footer = "\r\n--" + boundary + "--\r\n";
			formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));

			// Dump the Stream into a byte[]
			formDataStream.Position = 0;
			byte[] formData = new byte[formDataStream.Length];
			formDataStream.Read(formData, 0, formData.Length);
			formDataStream.Close();

			return formData;
		}

		public class FileParameter
		{
			public byte[] File { get; set; }
			public string FileName { get; set; }
			public string ContentType { get; set; }
			public FileParameter(byte[] file) : this(file, null) { }
			public FileParameter(byte[] file, string filename) : this(file, filename, null) { }
			public FileParameter(byte[] file, string filename, string contenttype)
			{
				File = file;
				FileName = filename;
				ContentType = contenttype;
			}
		}
	}

	public class ConsoleSpiner
	{
		int counter;
		public ConsoleSpiner()
		{
			counter = 0;
		}
		public void Turn()
		{
			counter++;
			switch (counter % 4)
			{
				case 0: Console.Write("/"); counter = 0; break;
				case 1: Console.Write("-"); break;
				case 2: Console.Write("\\"); break;
				case 3: Console.Write("|"); break;
			}
			Thread.Sleep(100);
			Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
		}
	}
	#endregion
}
